﻿using System;
using System.Text.RegularExpressions;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace TestProject1
{
    /// <summary>
    /// Directions
    /// </summary>
    public enum Heading
    {
        N = 0,
        E = 1,
        S = 2,
        W = 3
    }

    public class Rover
    {
        public int PosX { get; private set; }
        public int PosY { get; private set; }
        public int MaxPosX { get; private set; }
        public int MaxPosY { get; private set; }
        public Heading Heading { get; private set; }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="rvPosString">Start position string</param>
        /// <param name="maxPosX">X Size on plateu</param>
        /// <param name="maxPosY">Y Size on plateu</param>
        public Rover(string rvPosString, int maxPosX, int maxPosY)
        {
            var rvPosStringValues = rvPosString.Trim().Split(' ');
            if(!Regex.IsMatch(rvPosString, @"\d+ \d+ [NESW]"))
            {
                throw new ArgumentException("Invalid position value");
            }

            MaxPosX = maxPosX;
            MaxPosY = maxPosY;
            PosX = int.Parse(rvPosStringValues[0]);
            PosY = int.Parse(rvPosStringValues[1]);
            Heading = (Heading)Enum.Parse(typeof(Heading), rvPosStringValues[2]);
        }

        /// <summary>
        /// Process command sequence
        /// </summary>
        /// <param name="commands"></param>
        public void ExecuteCommands(string commands)
        {
            foreach (var command in commands.Trim())
                ExecuteCommand(command);
        }

        /// <summary>
        /// Process single command
        /// </summary>
        /// <param name="command"></param>
        public void ExecuteCommand(char command)
        {
            switch (command)
            {
                // Turn left
                case 'L':
                    Heading = (Heading == Heading.N) ? Heading.W : Heading - 1;
                    break;

                // Turn right
                case 'R':
                    Heading = (Heading == Heading.W) ? Heading.N : Heading + 1;
                    break;

                // Move
                case 'M':
                    switch (Heading)
                    {
                        case Heading.N:
                            if(PosY == MaxPosY)
                                throw new ApplicationException("I'm falling off plateu!!!");
                            PosY += 1;
                            break;

                        case Heading.S:
                            if (PosY == 0)
                                throw new ApplicationException("I'm falling off plateu!!!");
                            PosY -= 1;
                            break;

                        case Heading.W:
                            if (PosX == 0)
                                throw new ApplicationException("I'm falling off plateu!!!");
                            PosX -= 1;
                            break;

                        case Heading.E:
                            if (PosX == MaxPosX)
                                throw new ApplicationException("I'm falling off plateu!!!");
                            PosX += 1;
                            break;

                        default:
                            throw new ApplicationException("Invalid heading");
                    }
                    break;

                default:
                    throw new ArgumentException("Invalid command");   
            }
        }

        /// <summary>
        /// Reports current position
        /// </summary>
        /// <returns></returns>
        public string ReportPosition()
        {
            return String.Format("{0} {1} {2}", PosX, PosY, Heading);
        }
    }

    /// <summary>
    /// Processes input command string and retuns final rover positions
    /// </summary>
    public class RoverDriver
    {
        public string ProcessCommands(string inputCommands)
        {
            var lines = inputCommands.Split('\n');
            
            // get coordinate grid size
            var coordinateLine = lines[0];

            if (!Regex.IsMatch(coordinateLine, @"\d+ \d+"))
            {
                throw new ArgumentException("Invalid coordinate grid size");
            }
            var coordinateLineValues = coordinateLine.Trim().Split(' ');

            var maxX = int.Parse(coordinateLineValues[0]);
            var maxY = int.Parse(coordinateLineValues[1]);

            var rover1Position = lines[1];
            var rover1Commands = lines[2];

            var rover2Position = lines[3];
            var rover2Commands = lines[4];


            var rover1 = new Rover(rover1Position, maxX, maxY);
            rover1.ExecuteCommands(rover1Commands);

            var rover2 = new Rover(rover2Position, maxX, maxY);
            rover2.ExecuteCommands(rover2Commands);

            return String.Format("{0}\n{1}", rover1.ReportPosition(), rover2.ReportPosition());
        }
    }


    /// <summary>
    /// Summary description for UnitTest1
    /// </summary>
    [TestClass]
    public class UnitTests
    {
       
        [TestMethod]
        public void TestSampleCommands()
        {
            const string testData = @"5 5
                1 2 N
                LMLMLMLMM
                3 3 E
                MMRMMRMRRM";

            Assert.AreEqual("1 3 N\n5 1 E", new RoverDriver().ProcessCommands(testData));
        }
    }
}
